package com.smedi.ismedi.organization.core.port.adapter.persistence.repository.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.service.IService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.smedi.ismedi.constructionproject.api.dto.response.resp.ProjectResp;
import com.smedi.ismedi.database.starter.annotation.SkipSqlPermission;
import com.smedi.ismedi.organization.core.domain.aggregatemodel.HrOrganization;
import com.smedi.ismedi.organization.core.domain.aggregatemodel.dto.OrganizationQuery;
import com.smedi.ismedi.organization.core.domain.aggregatemodel.model.DingOrg;
import com.smedi.ismedi.organization.core.domain.aggregatemodel.model.Organization;
import com.smedi.ismedi.organization.core.domain.repository.HrOrganizationRepository;
import com.smedi.ismedi.organization.core.infrastructure.constant.CustomError;
import com.smedi.ismedi.organization.core.port.adapter.convert.AdapterConverter;
import com.smedi.ismedi.organization.core.port.adapter.persistence.dto.ProjectQuery;
import com.smedi.ismedi.organization.core.port.adapter.persistence.model.HrOrganizationEntity;
import com.smedi.ismedi.organization.core.port.adapter.persistence.mybatis.mapper.HrOrganizationMapper;
import com.smedi.ismedi.organization.core.port.adapter.service.ConstructionProjectRemoteApiService;
import com.smedi.ismedi.organization.core.port.adapter.service.PersonnelRemoteApiService;
import com.smedi.ismedi.web.starter.exception.LogicException;
import com.smedi.ismedi.web.starter.util.DozerUtil;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Repository;

import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Repository
@AllArgsConstructor
public class HrOrgRepositoryImpl extends ServiceImpl<HrOrganizationMapper, HrOrganizationEntity> implements HrOrganizationRepository, IService<HrOrganizationEntity> {
    private final DozerUtil dozerUtil;

    private final PersonnelRemoteApiService personnelRemoteApiService;

    private final AdapterConverter adapterConverter;

    private final ConstructionProjectRemoteApiService constructionProjectRemoteApiService;

    @Override
    public long updateHrOrgByShortName(String shortName, String dingDeptKey) {
        return this.getBaseMapper().updateDingDeptKeyByShortName(shortName, dingDeptKey);
    }

    // 根据组织id查询记录
    @Override
    public HrOrganization selectByHrOrganizationId(Long hrOrganizationId) {
        HrOrganizationEntity row = this.getBaseMapper().selectById(hrOrganizationId);
        return dozerUtil.convertor(row, HrOrganization.class);
    }

    @Override
    @SkipSqlPermission
    public List<HrOrganization> selectByHrOrganizationIds(List<Long> hrOrganizationIds) {
        LambdaQueryWrapper<HrOrganizationEntity> queryWrapper = new LambdaQueryWrapper<>();

        queryWrapper.in(HrOrganizationEntity::getId, hrOrganizationIds);
        List<HrOrganizationEntity> hrOrganizationEntities = this.getBaseMapper().selectList(queryWrapper);

        return dozerUtil.convertor(hrOrganizationEntities, HrOrganization.class);
    }

    @Override
    public List<HrOrganization> queryAll() {
        List<HrOrganizationEntity> hrOrganizationEntities = this.getBaseMapper().selectList(null);

        return dozerUtil.convertor(hrOrganizationEntities, HrOrganization.class);
    }

    @Override
    @SkipSqlPermission
    public List<HrOrganization> queryAllSkipSql() {
        List<HrOrganizationEntity> hrOrganizationEntities = this.getBaseMapper().selectList(null);

        return dozerUtil.convertor(hrOrganizationEntities, HrOrganization.class);
    }

    @Override
    public HrOrganization doInsert(HrOrganization data) {
        HrOrganizationEntity hrOrganizationEntity = dozerUtil.convertor(data, HrOrganizationEntity.class);
        this.getBaseMapper().insert(hrOrganizationEntity);
        return dozerUtil.convertor(hrOrganizationEntity, HrOrganization.class);
    }

    @Override
    public HrOrganization doUpdate(HrOrganization data) {
        HrOrganizationEntity hrOrganizationEntity = dozerUtil.convertor(data, HrOrganizationEntity.class);
        this.getBaseMapper().updateById(hrOrganizationEntity);
        return dozerUtil.convertor(hrOrganizationEntity, HrOrganization.class);
    }

    @Override
    public void doDelete(HrOrganization data) {
        // 判断这条数据是否已经被删除
        HrOrganizationEntity row = this.getById(data.getHrOrganizationId());
        if (row != null) {
            this.getBaseMapper().deleteById(data.getHrOrganizationId()); // 删除
        } else {
            throw LogicException.raise(CustomError.HR_ORGANIZATION_NOT_EXIST);
        }
    }

    // 查询组织的根节点
    @Override
    public HrOrganization selectHrOrganizationRoot() {
        HrOrganizationEntity hrOrganizationEntity = this.getBaseMapper().selectRoot();
        return dozerUtil.convertor(hrOrganizationEntity, HrOrganization.class);
    }

    @Override
    public List<HrOrganization> selectByParentId(Long hrOrganizationId) {
        QueryWrapper<HrOrganizationEntity> wrapper = new QueryWrapper();
        wrapper.eq("parent_id", hrOrganizationId);
        wrapper.orderByAsc("display_order", "id");
        List<HrOrganizationEntity> rows = this.getBaseMapper().selectList(wrapper);
        return dozerUtil.convertor(rows, HrOrganization.class);
    }

    @Override
    public List<HrOrganization> selectAllRoots() {
        QueryWrapper<HrOrganizationEntity> wrapper = new QueryWrapper<>();
        wrapper.eq("is_root", true);
        wrapper.orderByAsc("display_order", "id");
        List<HrOrganizationEntity> rows = this.getBaseMapper().selectList(wrapper);
        return dozerUtil.convertor(rows, HrOrganization.class);
    }

    @Override
    public int selectFullNameCount(String fullName, Long hrOrganizationId) {
        QueryWrapper<HrOrganizationEntity> wrapper = new QueryWrapper();
        wrapper.eq("full_name", fullName);
        if (hrOrganizationId != null) {
            wrapper.ne("id", hrOrganizationId);
        }
        return this.getBaseMapper().selectCount(wrapper);
    }

    @Override
    public int selectShortNameCount(String shortName, Long hrOrganizationId) {
        QueryWrapper<HrOrganizationEntity> wrapper = new QueryWrapper();
        wrapper.eq("short_name", hrOrganizationId);
        if (hrOrganizationId != null) {
            wrapper.ne("id", hrOrganizationId);
        }
        return this.getBaseMapper().selectCount(wrapper);
    }

    @Override
    public int selectOrganizationCodeCount(String orgCode, Long hrOrganizationId) {
        QueryWrapper<HrOrganizationEntity> wrapper = new QueryWrapper();
        wrapper.eq("organization_code", orgCode);
        if (hrOrganizationId != null) {
            wrapper.ne("id", hrOrganizationId);
        }
        return this.getBaseMapper().selectCount(wrapper);
    }

    @Override
    public List<HrOrganization> selectByFullNameLike(String fullName) {
        QueryWrapper<HrOrganizationEntity> wrapper = new QueryWrapper();
        wrapper.like("full_name", fullName).orderByAsc("id");
        return dozerUtil.convertor(this.getBaseMapper().selectList(wrapper), HrOrganization.class);
    }

    @Override
    public List<HrOrganization> selectByFullNameList(List<String> fullNameList) {
        QueryWrapper<HrOrganizationEntity> wrapper = new QueryWrapper();
        wrapper.in("full_name", fullNameList).orderByAsc("id");
        return dozerUtil.convertor(this.getBaseMapper().selectList(wrapper), HrOrganization.class);
    }

    @Override
    @SkipSqlPermission
    public List<HrOrganization> selectHrOrganizationByTypeList(List<String> typeList) {
        QueryWrapper<HrOrganizationEntity> wrapper = new QueryWrapper<>();
        wrapper.in("type", typeList).orderByAsc("display_order").orderByAsc("id");
        return dozerUtil.convertor(this.getBaseMapper().selectList(wrapper), HrOrganization.class);
    }

    @Override
    public List<HrOrganization> selectAll() {
        QueryWrapper<HrOrganizationEntity> wrapper = new QueryWrapper<>();
        wrapper.orderByAsc("id");
        return dozerUtil.convertor(this.getBaseMapper().selectList(wrapper), HrOrganization.class);
    }

    @Override
    public List<HrOrganization> getAllHrOrganization() {
        QueryWrapper<HrOrganizationEntity> wrapper = new QueryWrapper();
        wrapper.eq("is_deleted", false);

        return dozerUtil.convertor(this.getBaseMapper().selectList(wrapper), HrOrganization.class);
    }

    @Override
    public Organization getOrganizationOne(OrganizationQuery organizationQuery) {
        LambdaQueryWrapper<HrOrganizationEntity> lambdaQueryWrapper = new LambdaQueryWrapper<>();

        lambdaQueryWrapper.eq(ObjectUtils.isNotNull(organizationQuery.getId()), HrOrganizationEntity::getId, organizationQuery.getId());

        HrOrganizationEntity hrOrganizationEntity = this.getBaseMapper().selectOne(lambdaQueryWrapper);

        return adapterConverter.hrOrganizationEntityToOrganization(hrOrganizationEntity);
    }

    @Override
    public List<Organization> getOrganizationList(OrganizationQuery organizationQuery) {
        LambdaQueryWrapper<HrOrganizationEntity> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        boolean hasAboutIdQuery = false;
        Set<Long> organizationIds = new HashSet<>();
        if (CollectionUtils.isNotEmpty(organizationQuery.getIds())) {
            organizationIds.addAll(organizationQuery.getIds());
            hasAboutIdQuery = true;
        }
        if (ObjectUtils.isNotNull(organizationQuery.getProjectId())) {
            List<ProjectResp> projectResps = constructionProjectRemoteApiService.getProjectListWithoutToken(ProjectQuery.builder().ids(Collections.singletonList(organizationQuery.getProjectId())).build());
            if (!projectResps.isEmpty()) {
                if (organizationIds.isEmpty()) {
                    organizationIds.addAll(projectResps.stream().map(ProjectResp::getHrOrganizationId).collect(Collectors.toList()));
                }
                if (!organizationIds.isEmpty()) {
                    organizationIds.retainAll(projectResps.stream().map(ProjectResp::getHrOrganizationId).collect(Collectors.toList()));
                }
                hasAboutIdQuery = true;
            }
        }

        if (ObjectUtils.isNotEmpty(organizationQuery.getProjectIds())) {
            List<ProjectResp> projectResps = constructionProjectRemoteApiService.getProjectListWithoutToken(ProjectQuery.builder().ids(organizationQuery.getProjectIds()).build());
            if (!projectResps.isEmpty()) {
                if (organizationIds.isEmpty()) {
                    organizationIds.addAll(projectResps.stream().map(ProjectResp::getHrOrganizationId).collect(Collectors.toList()));
                }
                if (!organizationIds.isEmpty()) {
                    organizationIds.retainAll(projectResps.stream().map(ProjectResp::getHrOrganizationId).collect(Collectors.toList()));
                }
                hasAboutIdQuery = true;
            }
        }

        if (hasAboutIdQuery && organizationIds.isEmpty()) {
            return new ArrayList<>();
        }

        organizationQuery.setIds(new ArrayList<>(organizationIds));
        lambdaQueryWrapper.in(CollectionUtils.isNotEmpty(organizationQuery.getIds()), HrOrganizationEntity::getId, organizationQuery.getIds());
        lambdaQueryWrapper.in(CollectionUtils.isNotEmpty(organizationQuery.getTypeList()), HrOrganizationEntity::getType, organizationQuery.getTypeList());
        lambdaQueryWrapper.eq(ObjectUtils.isNotNull(organizationQuery.getShortName()), HrOrganizationEntity::getShortName, organizationQuery.getShortName());
        lambdaQueryWrapper.like(ObjectUtils.isNotNull(organizationQuery.getShortNameLike()), HrOrganizationEntity::getShortName, organizationQuery.getShortNameLike());
        lambdaQueryWrapper.eq(ObjectUtils.isNotNull(organizationQuery.getType()), HrOrganizationEntity::getType, organizationQuery.getType());
        lambdaQueryWrapper.in(CollectionUtils.isNotEmpty(organizationQuery.getFullNames()), HrOrganizationEntity::getFullName, organizationQuery.getFullNames());

        if(StringUtils.isNotBlank(organizationQuery.getTypeOr())){
            lambdaQueryWrapper.or().eq(HrOrganizationEntity::getType, organizationQuery.getTypeOr());
        }

        lambdaQueryWrapper.orderByAsc(true, HrOrganizationEntity::getDisplayOrder);
        lambdaQueryWrapper.orderByAsc(true, HrOrganizationEntity::getId);

        List<HrOrganizationEntity> hrOrganizationEntities = this.getBaseMapper().selectList(lambdaQueryWrapper);

        return adapterConverter.hrOrganizationEntityToOrganization(hrOrganizationEntities);
    }

    @Override
    @SkipSqlPermission
    public List<Organization> getOrganizationListWithoutToken(OrganizationQuery organizationQuery) {
        LambdaQueryWrapper<HrOrganizationEntity> lambdaQueryWrapper = new LambdaQueryWrapper<>();

        lambdaQueryWrapper.in(CollectionUtils.isNotEmpty(organizationQuery.getIds()), HrOrganizationEntity::getId, organizationQuery.getIds());
        lambdaQueryWrapper.like(ObjectUtils.isNotNull(organizationQuery.getShortNameLike()), HrOrganizationEntity::getShortName, organizationQuery.getShortNameLike());

        List<HrOrganizationEntity> hrOrganizationEntities = this.getBaseMapper().selectList(lambdaQueryWrapper);

        return adapterConverter.hrOrganizationEntityToOrganization(hrOrganizationEntities);
    }

    @Override
    public List<HrOrganization> selectHrOrganizationByTypeListNew(List<String> typeList, List<HrOrganization> hrOrganizationList) {
        List<HrOrganization> hrOrganizationList1 = new ArrayList<>();
        for (HrOrganization hrOrganization : hrOrganizationList) {
            if (typeList.contains(hrOrganization.getType())) {
                hrOrganizationList1.add(hrOrganization);
            }
        }
        return hrOrganizationList1;
    }

    @Override
    public List<DingOrg> getAllDingOrgList(List<Long> ids) {
        LambdaQueryWrapper<HrOrganizationEntity> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.in(CollectionUtils.isNotEmpty(ids), HrOrganizationEntity::getId, ids);
        List<HrOrganizationEntity> entities = this.getBaseMapper().selectList(lambdaQueryWrapper);
        return adapterConverter.hrOrganizationEntityToDingOrgs(entities);
    }
}